package com.middlegroup.subjectpay.service;

import com.alibaba.fastjson.JSONObject;
import com.middlegroup.common.enums.ConfigKeyEnums;
import com.middlegroup.common.model.NotifyRequest;
import com.middlegroup.common.model.ResponseEntity;
import com.middlegroup.common.utils.AesUtils;
import com.middlegroup.common.utils.Base64Utils;
import com.middlegroup.common.utils.RSAUtils;
import com.middlegroup.subjectpay.entity.SubjectNotifyPayLog;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.security.PrivateKey;
import java.util.Map;
import java.util.TreeMap;

/**
 *
 * @author pc
 * @date 2019/1/14
 */
@Service
@Slf4j
public class SubjectPayNotifyUtil {

    @Resource
    private RestTemplate restTemplate;
    @Resource
    private SubjectChannelConfigService subjectChannelConfigService;
    @Resource
    private SubjectNotifyPayLogService subjectNotifyPayLogService;

    public void notifyPay(String subjectCode, String method, NotifyRequest request) {

        //支付中台公钥加密aes 的key
        String platformPublicKey = subjectChannelConfigService.getConfigString(ConfigKeyEnums.SUBJECT_PAYPLATFORM_RSA_PUB_KEY.getCategory(),ConfigKeyEnums.SUBJECT_PAYPLATFORM_RSA_PUB_KEY.getName());

        //支付中心私钥签名
        String privateKeyStr = subjectChannelConfigService.getConfigString(ConfigKeyEnums.SUBJECT_RSA_PRI_KEY.getCategory(),ConfigKeyEnums.SUBJECT_RSA_PRI_KEY.getName());

        //支付中台回调地址
        String payPlatformNotifyUrl = subjectChannelConfigService.getConfigString(ConfigKeyEnums.SUBJECT_PAYPLATFORM_GATEWAY_URL.getCategory(),ConfigKeyEnums.SUBJECT_PAYPLATFORM_GATEWAY_URL.getName());

        if (StringUtils.isBlank(platformPublicKey)) {
            log.error("支付中心rsa公钥缺失!");
            return;
        }
        if (StringUtils.isBlank(privateKeyStr)) {
            log.error("支付主体rsa私钥缺失!");
            return;
        }
        if (StringUtils.isBlank(payPlatformNotifyUrl)) {
            log.error("支付中台回调地址缺失!");
            return;
        }

        String aesKey = RandomStringUtils.randomAlphanumeric(16);
        String reqData = null;
        String oldAesKey = aesKey;

        //使用明文aesKey加密业务数据
        try {
            reqData = AesUtils.encrypt(JSONObject.toJSONString(request), aesKey);
        } catch (Exception e) {
            log.error("Aes加密业务数据失败", e);
            return;
        }
        //使用商户公钥加密aesKey
        try {
            aesKey = new String(Base64Utils.encode(RSAUtils.encryptByPublicKey(aesKey.getBytes("UTF-8"), platformPublicKey)));
        } catch (Exception e) {
            log.error("RSA加密AES密钥失败", e);
            return;
        }

        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        postParameters.add("aesKey", aesKey);
        postParameters.add("subjectCode", subjectCode);
        postParameters.add("method", method);
        postParameters.add("reqData", reqData);

        Map<String, String> params = new TreeMap<String, String>();
        params.put("aesKey", aesKey);
        params.put("subjectCode", subjectCode);
        params.put("method", method);
        params.put("reqData", reqData);
        String jsoStr = JSONObject.toJSONString(params);

        //中台私钥签名
        PrivateKey privateKey = RSAUtils.readPrivateKey(privateKeyStr);
        String sign = null;
        try {
            sign = RSAUtils.sign("SHA1WithRSA", jsoStr.getBytes("UTF-8"), privateKey);
        } catch (Exception e) {
            log.error("中台私钥签名失败", e);
            return;
        }
        postParameters.add("sign", sign);
        ResponseEntity responseDto = null;
        //商户回调日志记录
        SubjectNotifyPayLog subjectNotifyPayLog = new SubjectNotifyPayLog();
        subjectNotifyPayLog.setStatus(0);
        subjectNotifyPayLog.setMerchantBillNo(request.getMerchantBillNo());
        subjectNotifyPayLog.setBillNo(request.getBillNo());
        subjectNotifyPayLog.setSubjectCode(subjectCode);
        subjectNotifyPayLog.setRequestText(JSONObject.toJSONString(postParameters));
        subjectNotifyPayLog.setBeginTime(System.currentTimeMillis());

        try {
            responseDto = restTemplate.postForObject(payPlatformNotifyUrl, postParameters, ResponseEntity.class);
            //商户响应200
            subjectNotifyPayLog.setStatus(1);
        } catch (Exception e) {
            log.error("回调通知支付中台异常,postParameters:{},error:{}",postParameters,e);
            //异常
            subjectNotifyPayLog.setStatus(3);
        }
        subjectNotifyPayLog.setEndTime(System.currentTimeMillis());
        String retData = null;
        try {
            retData = AesUtils.decrypt((String) responseDto.getData(), oldAesKey);
        } catch (Exception e) {
            log.error("解密商户响应数据失败!", e);
        }
        subjectNotifyPayLog.setResponseText(retData);
        subjectNotifyPayLogService.insert(subjectNotifyPayLog);

    }

}
